import gtk
from xml.sax.saxutils import unescape

class Error(gtk.Frame):
    def __init__(self, input, DOM):
        gtk.Frame.__init__(self)
        self.show()
        self.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse('#ff1400'))
        self.set_shadow_type(gtk.SHADOW_OUT)
        self.set_border_width(3)
        
        for i in ('type', 'value', 'trace'):
            try:
                t = unescape(DOM.getElementsByTagName(i)[0].childNodes[0].nodeValue)
            except Exception:
                t = ''
                setattr(self, i, t)
            setattr(self, i, t)
                

        self.VBox = gtk.VBox()
        self.VBox.show()
        self.add(self.VBox)
        
        l = gtk.Label('<span foreground="#ff1400" weight="bold" font_desc="10">Error</span>')
        l.set_use_markup(True)
        self.VBox.pack_start(l, expand = False)
        l.show()
        
        #create Labels for type and value
        labels = ((gtk.Label('<span weight="bold">Type:</span>'), gtk.Label(self.type)),
                  (gtk.Label('<span weight="bold">Value:</span>'), gtk.Label(self.value)))
                   
        for l, j in labels:
            l.show()
            l.set_use_markup(True)
            j.show()
            j.set_selectable(True)
            h = gtk.HBox()
            h.show()
            h.pack_start(l, expand=False)
            h.pack_start(j, expand=False)
            self.VBox.pack_start(h)
        
        #create Traceback widgets if traceback is available
        if self.trace:
            self.trace = eval(self.trace)   
            expander = gtk.Expander('<span weight="bold" style="italic">Traceback</span>')
            expander.show()
            expander.set_use_markup(True)
            self.VBox.pack_end(expander)
            
            expander.connect('enter-notify-event', self._event_mouseEnter)
            expander.connect('leave-notify-event', self._event_mouseLeave)
            
            v = gtk.VBox()
            v.show()
            expander.add(v)
            for t in self.trace:
                v.pack_start(Trace(t, input))
    
    def _event_mouseEnter(self, widget, event):
        '''
        Changes the curser to a plus when it enters.
        '''

        gtk.gdk.Window.set_cursor(self.window, gtk.gdk.Cursor(gtk.gdk.ARROW))
        
    def _event_mouseLeave(self, widget, event):
        '''
        Changes the cursor back to normal when it leaves.
        '''
        
        gtk.gdk.Window.set_cursor(self.window, gtk.gdk.Cursor(gtk.gdk.ARROW))            
        
        
class Trace(gtk.EventBox):
    def __init__(self, t, input):
        self.line = int(t[1])-1
        self.path = None
        self.target = None
        self.input = input
        self._getTarget(input, t[0])
        
        gtk.EventBox.__init__(self)
        self.show()
        self.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse('#ffffff'))
        
        self.connect('enter-notify-event', self._event_mouseEnter)
        self.connect('leave-notify-event', self._event_mouseLeave)
        self.connect('button-press-event', self._event_mouseClick)
        
        self.frame = gtk.Frame()
        self.frame.show()
        self.add(self.frame)
        self.frame.set_border_width(3)
        
        self.VBox = gtk.VBox()
        self.VBox.show()
        self.frame.add(self.VBox)
        labels = ((gtk.Label('<span weight="bold">Location:</span>'), gtk.Label('%s, line %s, in %s'%tuple(t[:3]))),
                  (gtk.Label('<span weight="bold">Code:</span>'), gtk.Label(t[3])))
        
        for l, j in labels:
            l.show()
            l.set_use_markup(True)
            j.show()
            h = gtk.HBox()
            h.show()
            h.pack_start(l, expand=False)
            h.pack_start(j, expand=False)
            self.VBox.pack_start(h)
    
    def _getTarget(self, input, ID):
        if ID.find('Input')==-1:
            self.path = ID
            return
        if input.ancestor.identifier=='Pythonsheet':
            self.target = input
            return
        
        pos = ID.find('id="')
        if pos==-1:
            return
        ID = int(ID[pos+4:ID.find('"', pos+5)])
        w = input.getAncestor('Worksheet')
        inputs = w.getChildren('Input', all=True)
        for i in inputs:
            if i.ID==ID:
                self.target = i
                return
            
    def _event_mouseEnter(self, widget, event):
        '''
        Changes the curser to a plus when it enters.
        '''

        gtk.gdk.Window.set_cursor(self.window, gtk.gdk.Cursor(gtk.gdk.HAND2))
        
    def _event_mouseLeave(self, widget, event):
        '''
        Changes the cursor back to normal when it leaves.
        '''
        
        gtk.gdk.Window.set_cursor(self.window, gtk.gdk.Cursor(gtk.gdk.ARROW))            
        
    
    def _event_mouseClick(self, widget, event):
        '''
        On left-click, sets the Focus on the code, where this Error happened. 
        '''
        
        if event.button==1:
            try:
                self.target.placeCursor(linePos=self.line)
            except Exception: 
                #try:
                    n = self.input.getAncestor('Notebook')
                    w = n.openSheet(self.path)
                    self.target = w.getChildren('Input')
                    self.target.placeCursor(linePos=self.line)
                #except Exception:
                    #TODO: give user hint that it's not working
                #    pass
            return True
        
        